import { AbstractHandler, Context, ErrorHandle, PostHandle, PrevHandle, Proxier } from '@/proxyUtils'

describe('proxyUtils', () => {

  const targetFn = async (suffix: string) => { return 'targetFn:' + suffix }

  let proxier: Proxier

  beforeEach(() => {
    proxier = new Proxier()
  })

  class TestHandler extends AbstractHandler {
    protected override prevHandle(): PrevHandle {
      return async () => {}
    }
    protected override postHandle(): PostHandle {
      return async () => {}
    }
    protected override errorHandle(): ErrorHandle {
      return async () => {}
    } 

  }

  describe('prevHandle', () => {

    test('前置方法有返回，应该不执行目标方法且返回前置方法返回值', async () => {
      class TestHandlerEx extends TestHandler {
        protected override prevHandle(): PrevHandle {
          return async (context: Context) => {
            return 'prevHandle:' + context.getArgs()[0]
          }
        }
      }

      proxier.addHandlers(
        new TestHandlerEx()
      )

      const result = await proxier.execute(targetFn, 'test')
      expect(result).toBe('prevHandle:test')
    })

    test('前置方法无返回，应该执行目标方法且返回目标方法返回值', async () => {
      proxier.addHandlers(
        new TestHandler()
      )

      const result = await proxier.execute(targetFn, 'test')
      expect(result).toBe('targetFn:test')
    })

    test('前置方法抛异常，应该执行目标方法且返回目标方法返回值', async () => {
      class TestHandlerEx extends TestHandler {
        protected override prevHandle(): PrevHandle {
          return async (context: Context) => {
            throw new Error('test')
          }
        }
      }

      proxier.addHandlers(
        new TestHandlerEx()
      )

      const result = await proxier.execute(targetFn, 'test')
      expect(result).toBe('targetFn:test')
    })

  })

  describe('postHandle', () => {

    test('后置方法有返回，应该返回后置方法返回值', async () => {
      class TestHandlerEx extends TestHandler {
        protected override postHandle(): PostHandle {
          return async (context: Context) => {
            return 'postHandle:' + context.getResult()
          }
        }
      }

      proxier.addHandlers(
        new TestHandlerEx()
      )

      const result = await proxier.execute(targetFn, 'test')
      expect(result).toBe('postHandle:targetFn:test')
    })

    test('后置方法无返回，应该返回目标方法返回值', async () => {
      proxier.addHandlers(
        new TestHandler()
      )

      const result = await proxier.execute(targetFn, 'test')
      expect(result).toBe('targetFn:test')
    })

    test('后置方法抛异常，应该返回目标方法返回值', async () => {
      class TestHandlerEx extends TestHandler {
        protected override postHandle(): PrevHandle {
          return async (context: Context) => {
            throw new Error('test')
          }
        }
      }
      proxier.addHandlers(
        new TestHandlerEx()
      )

      const result = await proxier.execute(targetFn, 'test')
      expect(result).toBe('targetFn:test')
    })

    test('前置方法返回，应该不执行后置方法', async () => {
      class TestHandlerEx extends TestHandler {
        protected override prevHandle(): PostHandle {
          return async (context: Context) => {
            return 'prevHandle:' + context.getArgs()[0]
          }
        }

        protected override postHandle(): PrevHandle {
          return async (context: Context) => {
            return 'postHandle:' + context.getResult()
          }
        }

      }
      proxier.addHandlers(
        new TestHandlerEx()
      )

      const result = await proxier.execute(targetFn, 'test')
      expect(result).toBe('prevHandle:test')
    })

  })

  describe('errorHandle', () => {

    const targetFnThrowError = async () => { throw new Error('targetFnError') }

    test('目标方法抛异常，应该执行错误方法', async () => {
      let errorMessage = ''
      class TestHandlerEx extends TestHandler {
        protected override errorHandle(): ErrorHandle {
          return async (context: Context) => {
            errorMessage = context.getError().message
          }
        }
      }

      proxier.addHandlers(
        new TestHandlerEx()
      )

      await expect(proxier.execute(targetFnThrowError)).rejects.toThrow('targetFnError')
      expect(errorMessage).toBe('targetFnError')
    })

    test('目标方法不抛异常，应该不执行错误方法', async () => {
      let errorMessage = ''
      class TestHandlerEx extends TestHandler {
        protected override errorHandle(): ErrorHandle {
          return async (context: Context) => {
            errorMessage = context.getError().message
          }
        }
      }

      proxier.addHandlers(
        new TestHandlerEx()
      )

      await expect(proxier.execute(targetFn, 'test')).resolves.toBe('targetFn:test')
      expect(errorMessage).toBe('')
    })

  })

})